package com.xzl.time.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.xzl.time.exceptions.MyException;
import com.xzl.time.mapper.ArticleMapper;
import com.xzl.time.mapper.NoticeMapper;
import com.xzl.time.pojo.Article;
import com.xzl.time.pojo.Notice;
import com.xzl.time.pojo.vo.UpdArticleVo;
import com.xzl.time.service.IArticleService;
import com.xzl.time.utils.MyEnum;
import com.xzl.tool.util.AnyUtils;
import com.xzl.tool.util.IdWorker;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * <p>
 * 文章 服务实现类
 * </p>
 *
 * @author zhoubin
 * @since 2021-12-03
 */
@Service
@Slf4j
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements IArticleService {

    @Autowired
    private ArticleMapper articleMapper;
    @Autowired
    private IdWorker idWorker;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 根据id查询文章
     *
     * @param id
     * @return
     */
    @Override
    public Article selectById(String id) {
        return articleMapper.selectById(id);
    }

    /**
     * 查询所有文章
     *
     * @param page
     * @param size
     * @param userName
     * @return
     */
    @Override
    public PageInfo<Article> selectList(Integer page, Integer size, String userName) {
        PageHelper.startPage(page, size);
        List<Article> articles = articleMapper.selectAll();
        //获取每个文章的点赞数
        for (Article item : articles) {
            //redis存储对文章的点赞用户
            String thumbUpArticleId = MyEnum.THUMBUP_ARTICLEID.getValue() + item.getId();
            try{
                Long size1 = redisTemplate.boundSetOps(thumbUpArticleId).size();
                item.setThumbup(Math.toIntExact(size1));
                Boolean member = redisTemplate.boundSetOps(thumbUpArticleId).isMember(userName);
                item.setThumbUpSate(member);
            }catch (Exception e){
                e.printStackTrace();
                log.error("thumbUpArticleId => "+thumbUpArticleId);
            }
        }
        PageInfo<Article> articlePageInfo = new PageInfo<>(articles);
        return articlePageInfo;
    }

    /**
     * 新增文章
     *
     * @param article
     * @return
     */
    @Override
    public Article addArticle(Article article) {
        if (StringUtils.isBlank(article.getContent())
                || StringUtils.isBlank(article.getUserid()))
            throw new MyException("参数异常！");
        article.setId(idWorker.nextId() + "");
        article.setCreatetime(AnyUtils.now());
        article.setUpdatetime(AnyUtils.now());
        article.setState("1");
        int insert = articleMapper.insert(article);

        //发送消息
        Notice notice = new Notice();
        notice.setId(idWorker.nextId() + "");
        notice.setOperatorId(article.getUserid());
        //接受消息的用户id在监听中设置
//        notice.setReceiverId(authorId);
        notice.setTargetType(MyEnum.ARTICLE_SUBSCRIBE_.getValue());
        notice.setTargetId(article.getId());
        notice.setType("user");
        notice.setState(false);

        String jsonNotice = JSON.toJSONString(notice);
        if (insert < 0) throw new MyException("发布失败！");
        //发消息给RabbitMq，就是新消息通知
        rabbitTemplate.convertAndSend(MyEnum.ARTICLE_SUBSCRIBE_.getValue(),
                article.getUserid(),
                jsonNotice);
        return article;
    }

    /**
     * 删除文章
     *
     * @param id
     */
    @Override
    public void delArticleById(String id) {
        Article article = articleMapper.selectById(id);
        articleMapper.deleteById(id);
    }

    /**
     * 修改文章
     *
     * @param article
     */
    @Override
    public void updArticleById(UpdArticleVo article) {
        article.setUpdatetime(AnyUtils.now());
        articleMapper.updArticleById(article);
    }

    /**
     * 通过用户名查询文章
     *
     * @param page
     * @param size
     * @param userName
     * @return
     */
    @Override
    public PageInfo<Article> getArticleByUserName(Integer page, Integer size, String userName) {
        PageHelper.startPage(page, size);
        List<Article> articles = articleMapper.getArticleByUserName(userName);
        articles.forEach(item -> {
            //redis存储对文章的点赞用户
            String thumbUpArticleId = MyEnum.THUMBUP_ARTICLEID.getValue() + item.getId();
            Long size1 = redisTemplate.boundSetOps(thumbUpArticleId).size();
            item.setThumbup(Math.toIntExact(size1));
            Boolean member = redisTemplate.boundSetOps(thumbUpArticleId).isMember(userName);
            item.setThumbUpSate(member);
        });
        PageInfo<Article> articlePageInfo = new PageInfo<>(articles);
        return articlePageInfo;
    }

    @Override
    public Boolean follow(String authorId, String userId) {
        Notice notice = new Notice();
        notice.setId(idWorker.nextId() + "");

        //1 创建Rabbit管理孚
        RabbitAdmin rabbitAdmin = new RabbitAdmin(rabbitTemplate.getConnectionFactory());
        //2声明交换机，处理新增文章消息
        DirectExchange exchange = new DirectExchange(MyEnum.ARTICLE_SUBSCRIBE_.getValue());
        rabbitAdmin.declareExchange(exchange);
        //3声明队列，每个用户都有自己的队列，通过用户id进行区分
        Queue queue = new Queue(MyEnum.ARTICLE_SUBSCRIBE_QUEUE_.getValue() + userId, true);
        // 4声明交换机和队列的绑定关系，需要确保队列只收到对应作者的新增文章消息
        // 通过路由键进行绑定作者，队列只收到绑定作者的文章消.息。
        Binding binding = BindingBuilder.bind(queue).to(exchange).with(authorId);

        String userKey = MyEnum.ARTICLE_SUBSCRIBE_QUEUE_.getValue() + userId;
        //是队列名，也是redis里面存放作者关注数的
        String authorKey = MyEnum.ARTICLE_AUTHOR_.getValue() + authorId;

        //是否已关注
        Boolean flag = redisTemplate.boundSetOps(userKey).isMember(authorId);
        if (flag) {
            redisTemplate.boundSetOps(userKey).remove(authorId);
            redisTemplate.boundSetOps(authorKey).remove(userId);
            rabbitAdmin.removeBinding(binding);
            notice.setCancelOrConfirm(-1);
        } else {
            redisTemplate.boundSetOps(userKey).add(authorId);
            redisTemplate.boundSetOps(authorKey).add(userId);
            rabbitAdmin.declareQueue(queue);
            rabbitAdmin.declareBinding(binding);
            notice.setAction("关注了你");
            notice.setCancelOrConfirm(1);
        }
        notice.setOperatorId(userId);
        notice.setReceiverId(authorId);
        notice.setTargetType(MyEnum.ARTICLE_SUBSCRIBE_.getValue());
        notice.setTargetId(authorId);
        notice.setType("sys");
        notice.setState(false);

        String jsonNotice = JSON.toJSONString(notice);

        //2 给作者添加单独消息队列
        //队列名称
        String thumbsUpArticle = MyEnum.ARTICLE_THUMBSUP.getValue() + authorId;
        Queue authorQueue = new Queue(thumbsUpArticle, true);
        rabbitAdmin.declareQueue(authorQueue);
        //将消息发送
        rabbitTemplate.convertAndSend(thumbsUpArticle, jsonNotice);
        return flag;
    }


    @Override
    @Transactional
    public int thumbsUp(String authorId, String thumbsUpUserId, String articleId) {
        Notice notice = new Notice();

        //redis存储对文章的点赞用户
        String thumbUpArticleId = MyEnum.THUMBUP_ARTICLEID.getValue() + articleId;
        //查询用户点赞信息，根据用户id和文章id
        Boolean flag = redisTemplate.boundSetOps(thumbUpArticleId).isMember(thumbsUpUserId);
        //判断查询到的结果是否为空
        if (flag) {
            //如果已经redis中存在这个文章的点赞，就在基础上减1数
            redisTemplate.boundSetOps(thumbUpArticleId).remove(thumbsUpUserId);
            //设置取消点赞内容
            notice.setCancelOrConfirm(-1);
        } else {
            //如果已经redis中存在这个文章的点赞数，就在基础上加1
            redisTemplate.boundSetOps(thumbUpArticleId).add(thumbsUpUserId);
            //设置点赞状态
            notice.setAction("点赞了您的作品");
            notice.setCancelOrConfirm(1);
        }

        //队列名称
        String thumbsUpArticle = MyEnum.ARTICLE_THUMBSUP.getValue() + authorId;
        //1 创建Rabbit管理孚
        RabbitAdmin rabbitAdmin = new RabbitAdmin(rabbitTemplate.getConnectionFactory());
        //2声明队列，每个用户都有自己的队列，通过用户id进行区分
        Queue queue = new Queue(thumbsUpArticle, true);
        rabbitAdmin.declareQueue(queue);

        notice.setId(idWorker.nextId() + "");
        notice.setOperatorId(thumbsUpUserId);
        notice.setReceiverId(authorId);
        notice.setTargetType(MyEnum.ARTICLE_THUMBSUP.getValue());
        notice.setTargetId(articleId);
        notice.setType("user");
        notice.setState(false);

        String jsonNotice = JSON.toJSONString(notice);
        //将消息发送
        rabbitTemplate.convertAndSend(thumbsUpArticle, jsonNotice);

        return notice.getCancelOrConfirm();
    }
}
